document.addEventListener("DOMContentLoaded", () => {
    const pageWidth = document.documentElement.clientWidth;
    const pageHeight = document.documentElement.clientHeight;
    const $app = document.querySelector("#app");
    const ctx = $app.getContext("2d");
    $app.width = pageWidth;
    $app.height = pageHeight;
    const width = 200;
    const height = 200;
    const cx = pageWidth / 2;
    const cy = pageHeight / 2;
    const x = cx - width / 2;
    const y = cy - height / 2;
    // 原点坐标
    const origin = [x + width / 2 , y + height / 2];
    // 是否旋转中
    let rotating = false;
    let aVector = null;
    let bVector = null;
    // 当前矩阵
    let currentMatrix = new Float32Array([
        1, 0, 0, 0,
        0, 1, 0, 0,
        0, 0, 1, 0,
        origin[0], origin[1], 0, 1
    ]);

    /**
     * 计算向量夹角，单位是弧度
     * @param {Array.<2>} av 
     * @param {Array.<2>} bv 
     * @returns {number}
     */
    function computedIncludedAngle(av, bv) {
        return Math.atan2(av[1], av[0]) - Math.atan2(bv[1], bv[0]);
    }

    /**
     * 渲染视图
     * @param {MouseEvent} e 鼠标对象 
     */
    function render(e) {
        // 清空画布内容
        ctx.clearRect(0, 0, ctx.canvas.width,  ctx.canvas.height);
        ctx.save();

        // 设置线段厚度，防止在高分屏下线段发虚的问题
        ctx.lineWidth = window.devicePixelRatio;

        // 设置变换矩阵
        ctx.setTransform(currentMatrix[0], currentMatrix[4], currentMatrix[1], currentMatrix[5], currentMatrix[12], currentMatrix[13]);
        
        // 绘制矩形
        ctx.strokeRect(-100, -100, 200, 200);

        // 设置圆圈的边框颜色和填充色
        ctx.fillStyle = "rgb(255, 255, 255)";
        ctx.strokeStyle = "rgb(6, 123, 239)";
    
        // 绘制矩形上边框中间的蓝色圆圈
        ctx.beginPath();
        ctx.arc(0, -100, 4, 0 , 2 * Math.PI);
        ctx.stroke();
        ctx.fill();

        // 绘制可以拖拽旋转的蓝色圆圈
        ctx.beginPath();
        ctx.arc(0, -130, 4, 0 , 2 * Math.PI);
        ctx.stroke();
        ctx.fill();

        // 判断是否拖拽旋转的蓝色圆圈
        const {pageX, pageY} = e ? e : {pageX: -99999, pageY: -9999};
        if (ctx.isPointInPath(pageX, pageY)) {
            rotating = true;
        }
        // 绘制链接两个圆圈的直线
        ctx.beginPath();
        ctx.fillStyle = "transparent";
        ctx.strokeStyle = "#000000";
        ctx.moveTo(0, -125);
        ctx.lineTo(0, -105);
        ctx.stroke();

        ctx.restore();
    }

    // 初次渲染
    render();

    // 监听画布的点击事件，如果点击了旋转圆圈，开始设置起始旋转向量
    $app.addEventListener("mousedown", (e) => {
        // 在渲染的过程中会判断是否点击了旋转圆圈，如果是，那么rotating会被设置为true
        render(e);
        if (!rotating) {
            return;
        }
        const { offsetX, offsetY } = e;
        aVector = [offsetX - origin[0], offsetY - origin[1]];
    });

    // 监听页面鼠标移动事件，如果处于旋转状态中，就计算出旋转矩阵，重新渲染
    document.addEventListener("mousemove", (e) => {
        // 如果不处于旋转状态，直接返回，避免不必要的无意义渲染
        if (!rotating) {
            return;
        }
        // 给画布添加旋转样式
        $app.classList.add("rotating");

        // 计算出当前坐标点与原点之间的向量
        const { offsetX, offsetY } = e;
        bVector = [offsetX - origin[0], offsetY - origin[1]];
        // 根据2个向量计算出旋转的弧度
        const angle = computedIncludedAngle(aVector, bVector);

        // 旋转矩阵
        const rotateMatrix = new Float32Array([
            Math.cos(angle), Math.sin(angle), 0, 0,
            -Math.sin(angle), Math.cos(angle), 0, 0,
            0, 0, 1, 0,
            0, 0, 0, 1
        ]);
        // 把当前渲染矩阵根据旋转矩阵，进行矩阵变换，得到画布的新渲染矩阵
        currentMatrix = glMatrix.mat4.multiply(
            glMatrix.mat4.create(),
            currentMatrix,
            rotateMatrix,
        );
        render(e);
        aVector = bVector;
    });

    // 鼠标弹起后，移除旋转状态
    document.addEventListener("mouseup", () => {    
        rotating = false;
        $app.classList.remove("rotating");
    });
});